package cn.jc.springframework.context.even;

import cn.hutool.extra.cglib.CglibUtil;
import cn.jc.springframework.beans.BeansException;
import cn.jc.springframework.beans.factory.BeanFactory;
import cn.jc.springframework.beans.factory.BeanFactoryAware;
import cn.jc.springframework.context.ApplicationEvent;
import cn.jc.springframework.context.ApplicationListener;
import cn.jc.springframework.utils.ClassUtils;


import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;

/**
 * ApplicationEventMulticaster接口的抽象实现，
 * 提供了基本的侦听器注册功能
 *
 * @Description:
 * @author: JC
 * @date: 2023/4/8 16:00
 */
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
    public final LinkedHashSet<ApplicationListener<ApplicationEvent>>
            applicationListeners =  new LinkedHashSet();

    private BeanFactory beanFactory;
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    /**
     * 方法主要是摘取符合广播事件中的监听处理器，具体过滤动作在 supportsEvent 方法中。
     * @param event
     * @return
     */
    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
        LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners){
            if(supportsEvent(listener, event)) allListeners.add(listener);
        }
        return allListeners;
    }



    /**
     * 监听器是否对该事件感兴趣
     * 主要包括对 Cglib、Simple 不同实例化需要获取目标
     * Class，Cglib 代理类需要获取父类的 Class，普通实例化的不需要。接下来就是通过
     * 提取接口和对应的 ParameterizedType 和 eventClassName，方便最后确认是否为
     * 子类和父类的关系，以此证明此事件归这个符合的类处理。
     * @param applicationListener
     * @param event
     * @return
     */
    private boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {

        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
        // 按照 CglibSubclassingInstantiationStrategy、
        // SimpleInstantiationStrategy 不同的实例化类型，需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ?
                listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();

        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + className);
        }
        // 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所
        // 示的类或接口是否相同，或是否是其超类或超接口。
        // isAssignableFrom 是用来判断子类和父类的关系的，或者接口的实现类和接口的关系的，
        // 默认所有的类的终极父类都是 Object。如果 A.isAssignableFrom(B)结果是 true，证明 B 可以转换成
        // 为 A,也就是 A 可以由 B 转换而来。
        return eventClassName.isAssignableFrom(event.getClass());
    }



    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
